
package vita;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartDocument;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XmlInterface {

	//No generics
	ArrayList<Person> persons;
	Document dom;
        String fileName;

	public XmlInterface() {
            persons = new ArrayList();
            dom=null;
            fileName=null;
        }

        public ArrayList<Person> getPersons() {
            return (ArrayList<Person>)persons.clone();
        }


        public void addPerson(int index, Person p) {
            persons.add(index, p);
        }

        public void deletePerson(int index[]) {
            for (int i=0; i<index.length; i++) {
                persons.remove(index[i]);
            }
        }

        public void readXmlFile(String fileName){
		//create a list to hold the Person objects
                this.fileName=fileName;

                //parse the xml file and get the dom object
		parseXmlFile();

		//get each employee element and create a Employee object
		parseDocument();
        }

        private void parseXmlFile(){
            //get the factory
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            try {
                //Using factory get an instance of document builder
                DocumentBuilder db = dbf.newDocumentBuilder();

                //parse using builder to get DOM representation of the XML file
                dom = db.parse(fileName);			
            } catch(ParserConfigurationException pce) {
                pce.printStackTrace();
            } catch(SAXException se) {
                se.printStackTrace();
            } catch(IOException ioe) {
                ioe.printStackTrace();
            }
	}

	
	private void parseDocument(){
            //get the root elememt
            Element docEle = dom.getDocumentElement();

            //get a nodelist of <person> elements
            NodeList nl = docEle.getElementsByTagName("Person");
            if(nl != null && nl.getLength() > 0) {
                for(int i = 0 ; i < nl.getLength();i++) {
                    //get the person element
                    Element el = (Element)nl.item(i);

                    //get the person object
                    Person e = getPerson(el);

                    //add it to list
                    persons.add(e);
                }
            }
        }


	/**
	 * I take an employee element and read the values in, create
	 * an Employee object and return it
	 * @param empEl
	 * @return
	 */
	private Person getPerson(Element empEl) {

            //for each <person> element get text or int values of
            //name ,id, age and name
            String name = getTextValue(empEl,"Name");
            int birthYear = getIntValue(empEl,"BirthYear");
            int deathYear = getIntValue(empEl,"DeathYear");
            String commemorationMonth = getTextValue(empEl,"CommemorationMonth");
            String commemorationDay = getTextValue(empEl,"CommemorationDay");
            String tags = getTextValue(empEl,"Tags");
            String birthLocation = getTextValue(empEl,"BirthLocation");
            String lifeLocation = getTextValue(empEl,"LifeLocation");
            String deathLocation = getTextValue(empEl,"DeathLocation");
            String relicsLocation = getTextValue(empEl,"RelicsLocation");
            String lifeStory = getTextValue(empEl,"LifeStory");
            String connections = getTextValue(empEl,"Connections");
            ArrayList<String> icons = null;
            String iconsString = getTextValue(empEl,"Icons");
            if (iconsString != null) {
                icons = new ArrayList(Arrays.asList(iconsString.split(",")));
            }
            //Create a new Person with the value read from the xml nodes
            Person p = new Person(name,birthYear,deathYear,commemorationMonth,commemorationDay,tags,
                               birthLocation,lifeLocation,deathLocation,relicsLocation,
                               lifeStory,connections,icons);
            return p;
	}


	/**
	 * I take a xml element and the tag name, look for the tag and get
	 * the text content
	 * i.e for <employee><name>John</name></employee> xml snippet if
	 * the Element points to employee node and tagName is name I will return John
	 * @param ele
	 * @param tagName
	 * @return
	 */
	private String getTextValue(Element ele, String tagName) {
            String textVal = null;
            NodeList nl = ele.getElementsByTagName(tagName);
            if(nl != null && nl.getLength() > 0) {
                Element el = (Element)nl.item(0);
                textVal = el.getFirstChild().getNodeValue();
            }
            return textVal;
	}


	/**
	 * Calls getTextValue and returns a int value
	 * @param ele
	 * @param tagName
	 * @return
	 */
	private int getIntValue(Element ele, String tagName) {
		//in production application you would catch the exception
		return Integer.parseInt(getTextValue(ele,tagName));
	}


        public void writeXmlFile(String fileName) {
            XMLEventWriter eventWriter = null;
            try {
                // Create a XMLOutputFactory
                XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
                try {
                    eventWriter = outputFactory.createXMLEventWriter(new FileOutputStream(fileName));
                } catch (FileNotFoundException ex) {
                    Logger.getLogger(XmlInterface.class.getName()).log(Level.SEVERE, null, ex);
                }
                // Create a EventFactory
                XMLEventFactory eventFactory = XMLEventFactory.newInstance();
                XMLEvent end = eventFactory.createDTD("\n");
                // Create and write Start Tag
                StartDocument startDocument = eventFactory.createStartDocument();
                eventWriter.add(startDocument);
                eventWriter.add(end);
                eventWriter.add(eventFactory.createStartElement("", "", "Root"));
                eventWriter.add(end);

                Iterator it = persons.iterator();
		while(it.hasNext()) {
                    Person p = (Person) it.next();

                    // Create open tag
                    StartElement configStartElement = eventFactory.createStartElement("", "", "Person");
                    eventWriter.add(configStartElement);
                    eventWriter.add(end);

                    // Write the different nodes
                    createNode(eventWriter, "Name", p.getName());
                    createNode(eventWriter, "BirthYear", p.getBirthYear().toString());
                    createNode(eventWriter, "DeathYear", p.getDeathYear().toString());
                    createNode(eventWriter, "Tags", p.getTags());
                    createNode(eventWriter, "CommemorationMonth", p.getCommemorationMonth().toString());
                    createNode(eventWriter, "CommemorationDay", p.getCommemorationDay().toString());
                    createNode(eventWriter, "BirthLocation", p.getBirthLocation());
                    createNode(eventWriter, "LifeLocation", p.getLifeLocation());
                    createNode(eventWriter, "DeathLocation", p.getDeathLocation());
                    createNode(eventWriter, "RelicsLocation", p.getRelicsLocation());
                    createNode(eventWriter, "LifeStory", p.getLifeStory());
                    createNode(eventWriter, "Connections", p.getConnections());
                    String icons="NULL";
                    if (p.getIcons()!=null) {
                        Object[] iconArray=p.getIcons().toArray();
                        String item = (String)iconArray[0];
                        for (int i=1; i<iconArray.length; i++) {
                            item = item + "," + iconArray[i];
                        }
                        icons = item;
                    }
                    createNode(eventWriter, "Icons", icons);

                    // Create cose tag
                    eventWriter.add(eventFactory.createEndElement("", "", "Person"));
                    eventWriter.add(end);
                }

                eventWriter.add(eventFactory.createEndElement("", "", "Root"));
                eventWriter.add(end);
                eventWriter.add(eventFactory.createEndDocument());
                eventWriter.close();
            } catch (XMLStreamException ex) {
                Logger.getLogger(XmlInterface.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    eventWriter.close();
                } catch (XMLStreamException ex) {
                    Logger.getLogger(XmlInterface.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

        }

	private void createNode(XMLEventWriter eventWriter, String name, String value) throws XMLStreamException {

		XMLEventFactory eventFactory = XMLEventFactory.newInstance();
		XMLEvent end = eventFactory.createDTD("\n");
		XMLEvent tab = eventFactory.createDTD("\t");
		// Create Start node
		StartElement sElement = eventFactory.createStartElement("", "", name);
		eventWriter.add(tab);
		eventWriter.add(sElement);
		// Create Content
		Characters characters = eventFactory.createCharacters(value);
		eventWriter.add(characters);
		// Create End node
		EndElement eElement = eventFactory.createEndElement("", "", name);
		eventWriter.add(eElement);
		eventWriter.add(end);

	}


        /**
	 * Iterate through the list and print the 
	 * content to console
	 */
	public void printData(){
		
		System.out.println("Number of Persons = '" + persons.size() + "'.");
		
		Iterator it = persons.iterator();
		while(it.hasNext()) {
			System.out.println(it.next().toString());
		}
	}

}
